/*
 * test.cpp
 *
 *  Created on: 2010-06-13
 *      Author: Daniel
 */

#include "../inc/test.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

// porzadek column-major
inline int idx(int x, int y, int n, int m) {
	return x + y * n;
}

void _test_vector_copy(int(*func)(const Vector&, Vector&)) {
	Vector source(10);
	Vector dest(10);
	Vector test(5);

	/* Test error handling */
	assert(func(source, test) < 0);
	assert(func(test, dest) < 0);

	/* Test functionality */
	for (int i = 0; i < 10; i++) {
		source.set(i, (float) i);
	}

	assert(func(source, dest) == 0);

	for (int i = 0; i < 10; i++) {
		assert(source.get(i) == dest.get(i));
	}
}

void _test_vector_literal(int(*func)(Vector&, float, float, float)) {

	//	Vector dest(10);
	//
	//	/* Test error handling */
	//	assert(func(dest,-1,1,10,1)<0);
	//	assert(func(dest,0,1,10,1)<0);
	//
	//	assert(func(dest,10,10,1,1)<0);
	//	assert(func(dest,10,1,10,-1)<0);
	//	assert(func(dest,10,1,10,0)<0);
	//
	//	assert(func(dest,10,1,100,1)<0);
	//	assert(func(dest,10,100,1,-1)<0);
	//
	//	assert(func(dest,100,1,10,1)<0);
	//	assert(func(dest,100,10,1,-1)<0);
	//
	//	/* Test functionality */
	//	assert(func(dest,10,1,10,1) == 0);
	//	for (int i = 0; i < 10; i++) {
	//		assert(dest.get(i) == i+1);
	//	}
	//
	//	assert(func(dest,10,10,1,-1) == 0);
	//	for (int i = 0; i < 10; i++) {
	//		assert(dest.get(i) == 10-i);
	//	}
	//
	//	assert(func(dest,10,1,19,2) == 0);
	//	for (int i = 0; i < 10; i++) {
	//		assert(dest.get(i) == 2*i+1);
	//	}
}

void _test_vector_equal(int(*func)(const Vector&, const Vector&)) {
	Vector first(10);
	Vector second(10);

	/* Test error handling */
	Vector test(5);
	assert(func(first, test) < 0);
	assert(func(test, second) < 0);

	/* Test functionality */
	for (int i = 0; i < 10; i++) {
		first.set(i, (float) i);
	}
	assert(func(first, second) == 0);

	for (int i = 0; i < 10; i++) {
		first.set(i, (float) i);
		second.set(i, (float) i);
	}
	assert(func(first, second) == 1);
}

void _test_vector_nequal(int(*func)(const Vector&, const Vector&)) {
	Vector first(10);
	Vector second(10);

	/* Test error handling */
	Vector test(5);
	assert(func(first, test) < 0);
	assert(func(test, second) < 0);

	/* Test functionality */
	for (int i = 0; i < 10; i++) {
		first.set(i, (float) i);
	}
	assert(func(first, second) == 1);

	for (int i = 0; i < 10; i++) {
		first.set(i, (float) i);
		second.set(i, (float) i);
	}
	assert(func(first, second) == 0);
}

void _test_vector_plus_vector(int(*func)(Vector&, const Vector&, const Vector&)) {
	Vector result(10);
	Vector first(10);
	Vector second(10);

	Vector test(5);
	assert(func(test, first, second) < 0);
	assert(func(result, test, second) < 0);
	assert(func(result, first, test) < 0);

	for (int i = 0; i < 10; i++) {
		first.set(i, (float) i);
		second.set(i, (float) i);
	}

	assert(func(result, first, second) == 0);

	for (int i = 0; i < 10; i++) {
		assert(result.get(i) == first.get(i) + second.get(i));
	}
}

void _test_vector_minus_vector(
		int(*func)(Vector&, const Vector&, const Vector&)) {
	Vector result(10);
	Vector first(10);
	Vector second(10);

	Vector test(5);
	assert(func(test, first, second) < 0);
	assert(func(result, test, second) < 0);
	assert(func(result, first, test) < 0);

	for (int i = 0; i < 10; i++) {
		first.set(i, 2 * (float) i);
		second.set(i, (float) i);
	}

	assert(func(result, first, second) == 0);

	for (int i = 0; i < 10; i++) {
		assert(result.get(i) == first.get(i) - second.get(i));
	}
}

void _test_matrix_times_vector(
		int(*func)(Vector&, const Matrix&, const Vector&)) {
	Vector result(10);
	Matrix matrix(10, 10);
	Vector vector(10);

	Matrix test1(10, 20);
	assert(func(result, test1, vector) < 0);
	Matrix test2(10, 20);
	assert(func(result, test1, vector) < 0);

	for (int i = 0; i < 10; i++) {
		vector.set(i, (float) i);

		for (int j = 0; j < 10; j++) {
			matrix.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(result, matrix, vector) == 0);

	for (int i = 0; i < 10; i++) {
		float val = 0;
		for (int j = 0; j < 10; j++) {
			val += matrix.get(i, j) * vector.get(j);
		}
		assert(result.get(i) == val);
	}
}

void _test_vector_times_matrix(
		int(*func)(Vector&, const Matrix&, const Vector&)) {
	Vector result(10);
	Matrix matrix(10, 10);
	Vector vector(10);

	Matrix test1(10, 20);
	assert(func(result, test1, vector) < 0);
	Matrix test2(10, 20);
	assert(func(result, test1, vector) < 0);

	for (int i = 0; i < 10; i++) {
		vector.set(i, (float) i);

		for (int j = 0; j < 10; j++) {
			matrix.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(result, matrix, vector) == 0);

	for (int i = 0; i < 10; i++) {
		float val = 0;
		for (int j = 0; j < 10; j++) {
			val += matrix.get(j, i) * vector.get(j);
		}
		assert(result.get(i) == val);
	}
}

void _test_matrix_copy(int(*func)(const Matrix&, Matrix&)) {

	Matrix source(10, 10);
	Matrix dest(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(source, test1) < 0);
	assert(func(source, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			source.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(source, dest) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			assert(source.get(i, j) == dest.get(i, j));
		}
	}
}

void _test_matrix_equal(int(*func)(const Matrix&, const Matrix&)) {

	Matrix first(10, 10);

	Matrix second(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(first, test1) < 0);
	assert(func(first, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(first, second) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i + (float) j);
			second.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(first, second) == 1);
}

void _test_matrix_nequal(int(*func)(const Matrix&, const Matrix&)) {

	Matrix first(10, 10);
	Matrix second(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(first, test1) < 0);
	assert(func(first, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(first, second) == 1);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i + (float) j);
			second.set(i, j, (float) i + (float) j);
		}
	}

	assert(func(first, second) == 0);
}

void _test_matrix_plus_matrix(int(*func)(Matrix&, const Matrix&, const Matrix&)) {

	Matrix result(10, 10);
	Matrix first(10, 10);
	Matrix second(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(test1, first, second) < 0);
	assert(func(result, test1, second) < 0);
	assert(func(result, first, test1) < 0);
	assert(func(test2, first, second) < 0);
	assert(func(result, test2, second) < 0);
	assert(func(result, first, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i);
			second.set(i, j, (float) j);
		}
	}

	assert(func(result, first, second) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			assert(result.get(i, j) == first.get(i, j) + second.get(i, j));
		}
	}
}

void _test_matrix_minus_matrix(
		int(*func)(Matrix&, const Matrix&, const Matrix&)) {

	Matrix result(10, 10);
	Matrix first(10, 10);
	Matrix second(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(test1, first, second) < 0);
	assert(func(result, test1, second) < 0);
	assert(func(result, first, test1) < 0);
	assert(func(test2, first, second) < 0);
	assert(func(result, test2, second) < 0);
	assert(func(result, first, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i);
			second.set(i, j, (float) j);
		}
	}

	assert(func(result, first, second) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			assert(result.get(i, j) == first.get(i, j) - second.get(i, j));
		}
	}
}

void _test_matrix_times_matrix(
		int(*func)(Matrix&, const Matrix&, const Matrix&)) {

	Matrix result(10, 10);
	Matrix first(10, 10);
	Matrix second(10, 10);

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(test1, first, second) < 0);
	assert(func(result, test1, second) < 0);
	assert(func(result, first, test1) < 0);
	assert(func(test2, first, second) < 0);
	assert(func(result, test2, second) < 0);
	assert(func(result, first, test2) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			first.set(i, j, (float) i);
			second.set(i, j, (float) j);
		}
	}

	assert(func(result, first, second) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			float val = 0;
			for (int k = 0; k < 10; k++) {
				val += first.get(i, k) * second.get(k, j);
			}
			assert(result.get(i, j) == val);
		}
	}
}

void _test_scalar_times_vector(int(*func)(Vector&, const Vector&, float)) {

	Vector result(10);
	Vector vector(10);
	float scalar = 5;

	Vector test(5);
	assert(func(test, vector, scalar) < 0);
	assert(func(result, test, scalar) < 0);

	for (int i = 0; i < 10; i++) {
		vector.set(i, (float) i);
	}

	assert(func(result, vector, scalar) == 0);
	for (int i = 0; i < 10; i++) {
		assert(result.get(i) == scalar * vector.get(i));
	}
}

void _test_scalar_times_matrix(int(*func)(Matrix&, const Matrix&, float)) {
	Matrix result(10, 10);
	Matrix matrix(10, 10);
	float scalar = 5;

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(result, test1,scalar) < 0);
	assert(func(result, test2,scalar) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			matrix.set(i, j, (float) i);
		}
	}

	assert(func(result, matrix, scalar) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			assert(result.get(i, j) == scalar * matrix.get(i, j));
		}
	}
}

void _test_vector_div_scalar(int(*func)(Vector&, const Vector&, float)) {

	Vector result(10);
	Vector vector(10);
	float scalar = 5;
	double epsilon = 0.00001;

	Vector test(5);
	assert(func(test, vector, scalar) < 0);
	assert(func(result, test, scalar) < 0);

	for (int i = 0; i < 10; i++) {
		vector.set(i, (float) i);
	}

	assert(func(result, vector, scalar) == 0);
	for (int i = 0; i < 10; i++) {
		assert(result.get(i) - vector.get(i) / scalar < epsilon);

	}
}

void _test_matrix_div_scalar(int(*func)(Matrix&, const Matrix&, float)) {
	Matrix result(10, 10);
	Matrix matrix(10, 10);
	float scalar = 5;
	double epsilon = 0.00001;

	Matrix test1(5, 10);
	Matrix test2(10, 5);
	assert(func(result, test1,scalar) < 0);
	assert(func(result, test2,scalar) < 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			matrix.set(i, j, (float) i);
		}
	}

	assert(func(result, matrix, scalar) == 0);

	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			assert(result.get(i, j) - scalar * matrix.get(i, j) < epsilon);
		}
	}
}
